/*
 * @Author: zhangshu
 * @email: shiliang.zhang@tuya.com
 * @LastEditors: Please set LastEditors
 * @file name: app_dev_register.c
 * @Description: 
 * @Copyright: HANGZHOU TUYA INFORMATION TECHNOLOGY CO.,LTD
 * @Company: http://www.tuya.com
 * @Date: 2022-02-08
 * @LastEditTime: 2022-02-08
 */
#include "app_dev_register.h"
#include "tal_network_mgr.h"

#ifndef GET_ARRAY_LEN
#define GET_ARRAY_LEN(x)    (SIZEOF(x) / SIZEOF(x[0]))
#endif

//identify attribute list
#define IDENTIFY_ATTR_LIST                                                                                                     \
    {0x0000, ATTR_INT16U_ATTRIBUTE_TYPE,    2, (ATTR_MASK_TOKEN_FAST), 0, (UINT8_T *)0x0005},   /* 12 / Identify / identify time*/ \
    {0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE,    2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0001},     /* 13 / Identify / cluster revision*/
//group attribute list
#define GROUP_ATTR_LIST \
    { 0x0000, ATTR_BITMAP8_ATTRIBUTE_TYPE,  1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00 }, /* 12 / Groups / name support*/\
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE,   2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0002 }, /* 13 / Groups / cluster revision*/
//scene attribute list
#define SCENE_ATTR_LIST \
    { 0x0000, ATTR_INT8U_ATTRIBUTE_TYPE,    1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00 }, /* 15 / Scenes / scene count*/\
    { 0x0001, ATTR_INT8U_ATTRIBUTE_TYPE,    1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00 }, /* 16 / Scenes / current scene*/\
    { 0x0002, ATTR_INT16U_ATTRIBUTE_TYPE,   2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0000 }, /* 16 / Scenes / current group*/\
    { 0x0003, ATTR_BOOLEAN_ATTRIBUTE_TYPE,  1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00 }, /* 17 / Scenes / scene valid*/\
    { 0x0004, ATTR_BITMAP8_ATTRIBUTE_TYPE,  1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00 }, /* 18 / Scenes / name support*/\
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE,   2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0002 }, /* 19 / Scenes / cluster revision*/
#define ONOFF_ATTR_LIST \
    { 0x0000, ATTR_BOOLEAN_ATTRIBUTE_TYPE,  1, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x00 } }, /* 20 / On/off / OnOff*/\
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE,   2, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x0002 } }, /* 24 / On/off / cluster revision*/
#define ONOFF_ATTR_LIST_SIMPLE \
    { 0x0000, ATTR_BOOLEAN_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x00 } }, /* OnOff */ \
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x0002 } }  /* cluster revision */

    // //power attribute
// CONST TAL_ATTR_T power_attr_list[] = {
//     POWER_ATTR_LIST
// };

// // identify attribute
// CONST TAL_ATTR_T identify_attr_list[] = {
//     IDENTIFY_ATTR_LIST
// };

// attribute list
CONST TAL_ATTR_T identify_attr_list[] = {
    IDENTIFY_ATTR_LIST
};
CONST TAL_ATTR_T group_attr_list[] = {
    GROUP_ATTR_LIST
};
CONST TAL_ATTR_T scene_attr_list[] = {
    SCENE_ATTR_LIST
};
CONST TAL_ATTR_T onoff_attr_list[] = {
    ONOFF_ATTR_LIST
};
CONST TAL_ATTR_T onoff_attr_list_simple[] = {
  ONOFF_ATTR_LIST_SIMPLE
};

#define DEF_CLUSTER_IDENTIFY_CLUSTER_ID(a) \
    {CLUSTER_IDENTIFY_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a))},
#define DEF_CLUSTER_GROUPS_CLUSTER_ID(a) \
    {CLUSTER_GROUPS_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a))},
#define DEF_CLUSTER_SCENES_CLUSTER_ID(a) \
    {CLUSTER_SCENES_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a))},
#define DEF_CLUSTER_ON_OFF_CLUSTER_ID(a) \
    {CLUSTER_ON_OFF_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a))},

// server cluster list
CONST TAL_CLUSTER_T onoff_1_ep_server_cluster_list[] = {
  DEF_CLUSTER_IDENTIFY_CLUSTER_ID(identify_attr_list)
  DEF_CLUSTER_GROUPS_CLUSTER_ID(group_attr_list)
  DEF_CLUSTER_SCENES_CLUSTER_ID(scene_attr_list)
  DEF_CLUSTER_ON_OFF_CLUSTER_ID(onoff_attr_list)
};
CONST TAL_CLUSTER_T onoff_2_ep_server_cluster_list[] = {
  DEF_CLUSTER_IDENTIFY_CLUSTER_ID(identify_attr_list)
  DEF_CLUSTER_GROUPS_CLUSTER_ID(group_attr_list)
  DEF_CLUSTER_SCENES_CLUSTER_ID(scene_attr_list)
  DEF_CLUSTER_ON_OFF_CLUSTER_ID(onoff_attr_list)
};
CONST TAL_CLUSTER_T onoff_3_ep_server_cluster_list[] = {
  DEF_CLUSTER_IDENTIFY_CLUSTER_ID(identify_attr_list)
  DEF_CLUSTER_GROUPS_CLUSTER_ID(group_attr_list)
  DEF_CLUSTER_SCENES_CLUSTER_ID(scene_attr_list)
  DEF_CLUSTER_ON_OFF_CLUSTER_ID(onoff_attr_list)
};
CONST TAL_CLUSTER_T onoff_4_ep_server_cluster_list[] = {
    DEF_CLUSTER_IDENTIFY_CLUSTER_ID(identify_attr_list)
    DEF_CLUSTER_GROUPS_CLUSTER_ID(group_attr_list)
    DEF_CLUSTER_SCENES_CLUSTER_ID(scene_attr_list)
    DEF_CLUSTER_ON_OFF_CLUSTER_ID(onoff_attr_list)

};

#define ONOFF_1_EP_SERVER_CLUSTER_NUM   GET_ARRAY_LEN(onoff_1_ep_server_cluster_list)
#define ONOFF_2_EP_SERVER_CLUSTER_NUM   GET_ARRAY_LEN(onoff_2_ep_server_cluster_list)
#define ONOFF_3_EP_SERVER_CLUSTER_NUM   GET_ARRAY_LEN(onoff_3_ep_server_cluster_list)
#define ONOFF_4_EP_SERVER_CLUSTER_NUM   GET_ARRAY_LEN(onoff_4_ep_server_cluster_list)

//endpoint descriptor
TAL_ENDPOINT_T dev_endpoint_desc[] = {
    {ONOFF_1_ENDPOINT, ZHA_PROFILE_ID, ZG_DEVICE_ID_ON_OFF_LIGHT, ONOFF_1_EP_SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&onoff_1_ep_server_cluster_list[0], 0, NULL},
    {ONOFF_2_ENDPOINT, ZHA_PROFILE_ID, ZG_DEVICE_ID_ON_OFF_LIGHT, ONOFF_2_EP_SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&onoff_2_ep_server_cluster_list[0], 0, NULL},
    {ONOFF_3_ENDPOINT, ZHA_PROFILE_ID, ZG_DEVICE_ID_ON_OFF_LIGHT, ONOFF_3_EP_SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&onoff_3_ep_server_cluster_list[0], 0, NULL},
    {ONOFF_4_ENDPOINT, ZHA_PROFILE_ID, ZG_DEVICE_ID_ON_OFF_LIGHT, ONOFF_4_EP_SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&onoff_4_ep_server_cluster_list[0], 0, NULL},
};

/**
 * @brief check if the cluster already in registertion list
 * NOTE: only for server clusters attributes
 *
 * @param[in] cluster_id: cluster id
 * @return TRUE if the cluster exists in registertion list or FALSE
 */
// BOOL_T is_server_cluster_valid(UINT16_T cluster_id)
// {
//     for (UINT8_T i = 0; i < SERVER_CLUSTER_NUM; i++) {
//         if (app_server_cluster_list[i].cluster_id == cluster_id) {
//             return TRUE;
//         }
//     }
//     return FALSE;
// }

/**
 * @brief check if the attribute  of cluster already in registertion list
 * NOTE: only for server clusters attributes
 *
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @return TRUE when in registertion list else FALSE
 */
// BOOL_T is_server_attribute_valid(UINT16_T cluster_id, UINT16_T attribute_id)
// {
//     for (UINT8_T i = 0; i < SERVER_CLUSTER_NUM; i++) {
//         if (app_server_cluster_list[i].cluster_id == cluster_id) {
//             for (UINT8_T j = 0; j < app_server_cluster_list[i].attr_sums; j++) {
//                 if (app_server_cluster_list[i].attr_list[j].attr_id == attribute_id) {
//                     return TRUE;
//                 }
//             }
//         }
//     }
//     return FALSE;
// }
#if 1
/**
 * @brief register router or sleep device
 * @return none
 */
STATIC VOID_T app_router_node_init(VOID_T)
{
    TAL_ZG_NODE_CFG_T node_config = {
        .node_type = ZG_ROUTER,//zigbee type, router, end device or sleep end device
        .tx_power = DEFAULT_TX_POWER,//set tx power
        .scan_interval = BEACON_SEND_INTERVAL_200MS,//beacon scan interval
        .scan_duration = ZG_SCAN_DURATION_3,//beacon scan interval 153.6 ms
    };
    //config zigbee node
    tal_zg_node_config(&node_config);
}
#endif
/**
 * @brief register router or sleep device
 * @return none
 */
STATIC VOID_T app_end_device_node_init(VOID_T)
{      // sleep end device node init
  TAL_ZG_NODE_CFG_T node_config = {
      .node_type                                                 = ZG_SLEEPY_END_DEVICE,
      .tx_power                                                  = 10,
      .scan_interval                                             = 100,
      .scan_duration                                             = ZG_SCAN_DURATION_3,
      .config.sleep_ed_cfg.poll_config.forever_flag              = 0,
      .config.sleep_ed_cfg.poll_config.fast_swicth_parent        = 1,
      .config.sleep_ed_cfg.poll_config.interval_ms               = 250,
      .config.sleep_ed_cfg.poll_config.max_failed_times          = 10,
      .config.sleep_ed_cfg.poll_config.duration_after_data_ms    = 1000,
      .config.sleep_ed_cfg.poll_config.duration_after_join_ms    = 60000,
      .config.sleep_ed_cfg.poll_config.duration_after_rejoin_ms  = 15000,
      .config.sleep_ed_cfg.rejoin_config.power_on_active         = 1,
      .config.sleep_ed_cfg.rejoin_config.send_data_active        = 1,
      .config.sleep_ed_cfg.rejoin_config.attempts                = 3,
      .config.sleep_ed_cfg.rejoin_config.interval                = 3000,
  };
 //config zigbee node
  tal_zg_node_config(&node_config);
}

/**
 * @brief config join strategy
 * @return none
 */
STATIC VOID_T dev_joined_config(VOID_T)
{
    TAL_ZG_JOIN_CFG_T join_config = {
        .auto_join_power_on_flag = FALSE,//defalut power on start join or not
        .auto_join_remote_leave_flag = TRUE,//default start join or not when receivew remote leave request
        .join_timeout = ZIGBEE_JOIN_TIMEOUT_MS,//join timeout times
    };
    //config join prameter
    TAL_PR_TRACE("====================================== tal_zg_join_config(&join_config) %d", tal_zg_join_config(&join_config));  
}

/**
 * @brief register zigbee parameter
 * @return none
 */
VOID_T dev_zigbee_init(VOID_T)
{
    //register zigbee endpoint
    tal_zg_endpoint_register(dev_endpoint_desc, GET_ARRAY_LEN(dev_endpoint_desc));

#if USE_SLEEP
    //zigbee node configuration
    app_end_device_node_init();
#else
app_router_node_init();
#endif

    //zigbee joining network configuration
    dev_joined_config();

    tal_zg_nwk_recovery_disable(TRUE);
    // tal_zg_nwk_recovery_disable(FALSE);
}

